package com.ys.utils.spring.interceptor;

import com.aliyun.openservices.shade.com.alibaba.fastjson.JSONObject;
import com.ys.utils.base.http.McodeHandler;
import com.ys.utils.base.http.RequestHandler;
import com.ys.utils.base.http.ResponseHandler;
import com.ys.utils.base.j2se.DateHandler;
import com.ys.utils.base.j2se.Logger;
import com.ys.utils.base.j2se.StringHandler;
import com.ys.utils.redis.Redis;
import com.ys.utils.redis.key.UserKey;
import com.ys.utils.spring.ServerUrl;
import com.ys.utils.spring.config.ResultCode;
import com.ys.utils.spring.config.SystemError;
import com.ys.utils.spring.properties.Config;
import com.ys.utils.spring.properties.SysConfig;
import com.ys.web.config.manager.UrlManager;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;

/**
 * @ 名称:
 * @ 创建人: dhf
 * @ 参数： url拦截器
 * @ 创建时间: 2022/5/11
 * @ 修改人和其它信息
 * @ 返回值:
 */
public class ServerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取uri 设置请求编码集
        long begin = System.currentTimeMillis();
        request.setCharacterEncoding("utf-8");
        request.setAttribute("system.time", System.currentTimeMillis());
        String uri = request.getRequestURI();
        String ip = RequestHandler.getIP(request);

        if(Config.pp.get("sys.black.ips").contains(ip)){
            ResponseHandler.write(ResponseHandler.error("500", "系统繁忙"), request, response);
        }

        //限制请求内容大小
        String rpid = UUID.randomUUID().toString();//生成请求编号
        if (request.getContentLength() > 1048576) {
            String error = "请求内容大小超过限制"+(1048576/1024)+"KB";
            Logger.info("%s [server]receive:[%s] %s", rpid, uri, error);
            ResponseHandler.write(ResponseHandler.error("6002", error), request, response);
            return false;
        }
        try{
            ipAllLimit(uri,ip);
            //各种认证
            ServerUrl serverUrl = auth(uri, request, response,ip);
            //模拟接口
            if(StringHandler.isNotEmpty(serverUrl) && serverUrl.ismock){
                ResponseHandler.write(Config.pp.get("mock."+serverUrl.url), request, response);
                return false;
            }
        } catch (Exception e) {
            SystemError error = SystemError.exp2Se(e);
            if(error.getRetcode() == ResultCode.SERVER_ERROR){
                Logger.error(uri, e);
            }
            ResponseHandler.write(ResponseHandler.error(error.getErrorCode(), error.getMessage()), request, response);
            return false;
        }
        //注入IP
        request.setAttribute("ip", ip);
        Logger.info("请求信息   Url：" + uri + " 请求时间  Times " + (System.currentTimeMillis()-begin) + "ms\n参数:  " + JSONObject.toJSONString(this.getaramsMaps(request.getParameterMap())) );
        return true;
    }

    //后置处理方法：原始方法运行后运行，如果原始方法被拦截，则不执行
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) // 如果处理器执行完成具有返回结果，可以读取到对应数据与页面信息进行调整
            throws Exception {

        System.out.println("后置运行");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        String s = (String) request.getSession().getAttribute("body");
        System.out.println(s);

    }
    public Map<String, Object> getaramsMaps(Map<String, String[]> params ) {
        Map<String, Object> paramsMaps = new HashMap<>();
        if(StringHandler.isEmpty(params) || params.size()<=0)
            return paramsMaps;
        Iterator<Map.Entry<String, String[]>> iterator =  params.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String[]> next = iterator.next();
            paramsMaps.put(next.getKey(), next.getValue()[0]);
        }
        return paramsMaps;
    }
    /**
     * 各种限制
     * 签名 + referer + 请求次数
     */
    private ServerUrl auth(String uri, HttpServletRequest request, HttpServletResponse response,String ip){
        //请求认证
        ServerUrl url = UrlManager.url(uri);
        if(null == url || url.loginAuth){
            String alias = request.getParameter("alias");
            String token = request.getParameter("token");
            String uid = Redis.str.get(UserKey.uidByToken(token));
            if(StringHandler.isEmpty(uid) || McodeHandler.from32Radix(alias)!=StringHandler.getLong(uid))
                SystemError.wrapBs("6007", Config.pp.get("6007"));
            request.setAttribute("uid", StringHandler.getLong(uid));
            //用户次数限制
            if(StringHandler.getLong(uid) > 0 && StringHandler.isNotEmpty(url) && url.userLimit){
                long min = DateHandler.getLongFormatDate(System.currentTimeMillis())/100000;
                Long limit = Redis.hash.hincrBy("AuthLimit_"+min,uid+"."+uri, 1,60);
                if(null != limit && limit > url.userCount){
                    Config.pp.put("sys.black.ips",Config.pp.get("sys.black.ips")+","+ip);
                    SysConfig.addBlackIp(","+ip);
                    Logger.error(String.format("频繁请求,IP:%s,路径：%s,用户：%s",ip,uri,uid));
                    SystemError.wrapBs("6008", "频繁操作，请稍后再试");
                }
            }
            return url;
        }
        return new ServerUrl();
    }

    private void ipAllLimit(String uri, String ip){
        long min = DateHandler.getLongFormatDate(System.currentTimeMillis())/100000;
        Long limit = Redis.hash.hincrBy("AuthLimit_"+min,ip.replaceAll("\\.",""), 1,60);
        if(null != limit && limit > StringHandler.getInt(Config.pp.get("sys.ip.all.limit"))){
//            Config.pp.put("sys.black.ips",Config.pp.get("sys.black.ips")+","+ip);
//            SysConfig.addBlackIp(","+ip);
            Logger.error(String.format("频繁请求,路径：%s,ip：%s",uri,ip));
//            SystemError.wrapBs("6008", "频繁操作，请稍后再试..");
        }
    }
}
